#include <json/json.h>
#include <string>


#define REFLECT_PP_FOREACH_1(f, _1) f(_1)
#define REFLECT_PP_FOREACH_2(f, _1, _2) f(_1); f(_2)
#define REFLECT_PP_FOREACH_3(f, _1, _2, _3) f(_1); f(_2); f(_3)
#define REFLECT_PP_FOREACH_4(f, _1, _2, _3, _4) f(_1); f(_2); f(_3); f(_4)
#define REFLECT_PP_FOREACH_5(f, _1, _2, _3, _4, _5) f(_1); f(_2); f(_3); f(_4); f(_5)
#define REFLECT_PP_FOREACH_6(f, _1, _2, _3, _4, _5, _6) f(_1); f(_2); f(_3); f(_4); f(_5); f(_6)
#define REFLECT_PP_FOREACH_7(f, _1, _2, _3, _4, _5, _6, _7) f(_1); f(_2); f(_3); f(_4); f(_5); f(_6); f(_7)
#define REFLECT_PP_FOREACH_8(f, _1, _2, _3, _4, _5, _6, _7, _8) f(_1); f(_2); f(_3); f(_4); f(_5); f(_6); f(_7); f(_8)
#define REFLECT_PP_FOREACH_9(f, _1, _2, _3, _4, _5, _6, _7, _8, _9) f(_1); f(_2); f(_3); f(_4); f(_5); f(_6); f(_7); f(_8); f(_9)
#define REFLECT_PP_FOREACH_10(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) f(_1); f(_2); f(_3); f(_4); f(_5); f(_6); f(_7); f(_8); f(_9); f(_10)

#define REFLECT_PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define REFLECT_PP_NARGS(...) REFLECT_PP_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define REFLECT_EXPAND(x) x 
#define REFLECT_CONCAT_2(x, y) x##y
#define REFLECT_CONCAT(x, y) REFLECT_CONCAT_2(x, y)
#define REFLECT_PP_FOREACH(f, ...) REFLECT_EXPAND(REFLECT_CONCAT(REFLECT_PP_FOREACH_, REFLECT_PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__))


template <class T>
struct reflect_trait{};

// 用宏简化模板特化
#define REFLECT_BEGIN(Type) \
template <> \
struct reflect_trait<Type> { \
    template<class Func> \
    static constexpr void for_each_members(Type& object, Func&& func) { \

#define REFLECT_PER_MEMBER(Member) \
    func(#Member, object.Member); 

#define REFLECT_END() \
    } \
}; \


// 用宏简化模板特化，支持不定参数个数
#define REFLECT(Type, ...)\
REFLECT_BEGIN(Type) \
REFLECT_PP_FOREACH(REFLECT_PER_MEMBER, __VA_ARGS__) \
REFLECT_END();

template <class T>
std::string serialize(T& object)
{
    Json::Value root;
    reflect_trait<T>::for_each_members(object, [&](const std::string& key, auto& value){
        root[key] = value;
    });

    return root.toStyledString();
}